﻿using System;
using System.Text;
using System.Security.Cryptography;

namespace JN.Utility
{
    public struct RSAKeyValue
    {
        public string Modulus;
        public string Exponent;
        public string P;
        public string Q;
        public string DP;
        public string DQ;
        public string InverseQ;
        public string D;
    }

    public class RSACrypto
    {
        private const string SPLIT_STRING = "@";

        public static void GenerateKeys(ref string xmlPrivateKey, ref string xmlPublicKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            xmlPrivateKey = rsa.ToXmlString(true);
            xmlPublicKey = rsa.ToXmlString(false);
        }

        public static string Encrypt(string xmlPrivateKeyPath, string data)
        {
            try
            {
                RSAKeyValue rsaPara = XmlExSerializer.DeserializeByFile<RSAKeyValue>(xmlPrivateKeyPath);
                if (string.IsNullOrEmpty(rsaPara.D) || string.IsNullOrEmpty(rsaPara.Modulus))
                    return string.Empty;

                return EncryptProcess(data, rsaPara.D, rsaPara.Modulus);
            }
            catch
            {
                return string.Empty;
            }
        }

        public static string Decrypt(string xmlPublicKeyPath, string data)
        {
            try
            {
                RSAKeyValue rsaPara = XmlExSerializer.DeserializeByFile<RSAKeyValue>(xmlPublicKeyPath);
                if (string.IsNullOrEmpty(rsaPara.Exponent) || string.IsNullOrEmpty(rsaPara.Modulus))
                    return string.Empty;

                return DecryptProcess(data, rsaPara.Exponent, rsaPara.Modulus);
            }
            catch
            {
                return string.Empty;
            }
        }

        /* 
         加密过程,其中d、n是RSACryptoServiceProvider生成的D、Modulus 
        */
        private static string EncryptProcess(string source, string d, string n)
        {
            byte[] N = Convert.FromBase64String(n);
            byte[] D = Convert.FromBase64String(d);
            BigInteger biN = new BigInteger(N);
            BigInteger biD = new BigInteger(D);
            return EncryptString(source, biD, biN);
        }

        /* 
         解密过程,其中e、n是RSACryptoServiceProvider生成的Exponent、Modulus 
        */
        private static string DecryptProcess(string source, string e, string n)
        {
            byte[] N = Convert.FromBase64String(n);
            byte[] E = Convert.FromBase64String(e);
            BigInteger biN = new BigInteger(N);
            BigInteger biE = new BigInteger(E);
            return DecryptString(source, biE, biN);
        }

        /* 
         功能：用指定的私钥(n,d)加密指定字符串source 
        */
        private static string EncryptString(string source, BigInteger d, BigInteger n)
        {
            int len = source.Length;
            int len1 = 0;
            int blockLen = 0;
            if ((len % 128) == 0)
                len1 = len / 128;
            else
                len1 = len / 128 + 1;
            string block = "";
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < len1; i++)
            {
                if (len >= 128)
                    blockLen = 128;
                else
                    blockLen = len;
                block = source.Substring(i * 128, blockLen);
                byte[] oText = System.Text.Encoding.Default.GetBytes(block);
                BigInteger biText = new BigInteger(oText);
                BigInteger biEnText = biText.modPow(d, n);
                string temp = biEnText.ToHexString();
                result.Append(temp).Append(SPLIT_STRING);
                len -= blockLen;
            }
            return result.ToString().TrimEnd(SPLIT_STRING.ToCharArray());
        }

        /* 
         功能：用指定的公钥(n,e)解密指定字符串source 
        */
        private static string DecryptString(string source, BigInteger e, BigInteger n)
        {
            StringBuilder result = new StringBuilder();
            string[] strarr1 = source.Split(SPLIT_STRING.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < strarr1.Length; i++)
            {
                string block = strarr1[i];
                BigInteger biText = new BigInteger(block, 16);
                BigInteger biEnText = biText.modPow(e, n);
                string temp = System.Text.Encoding.Default.GetString(biEnText.getBytes());
                result.Append(temp);
            }
            return result.ToString();
        }

    }
}
